package org.tony.sim.fmt;

import java.util.Arrays;

public abstract class Fmt extends Instruction {
    private static final int DIVIDE_LENGTH = 8;
    // 指令长度
    protected byte fmtLength = 0;
    // 从高位->低位按照顺序存储每一位的位置列表
    protected byte[] opcodeBits;

    protected Fmt(Module module, Category category, String name, String description, byte fmtLength, byte[] opcodeBits) {
        super(module, category, name, description);
        this.fmtLength = fmtLength;
        this.opcodeBits = opcodeBits;
    }

    public byte[] getOpcodeBits() {
        return Arrays.copyOf(this.opcodeBits, this.opcodeBits.length);
    }

    public byte getFmtLength() {
        return this.fmtLength;
    }

    /**
     * 获取整数中的某一段的值
     *
     * @param inst 输入整数
     * @param bits 要获取的位的位置列表
     * @return int 输出整数
     */
    protected int getBits(int inst, byte[] bits) {
        int ret = 0;
        for (byte b : bits) {
            ret <<= 1;
            ret |= getBit(inst, b);
        }
        return ret;
    }

    /**
     * 获取整数中某一位的值
     *
     * @param inst     输入整数
     * @param bitIndex 要获取的位的位置
     * @return int 输出整数
     */
    private int getBit(int inst, byte bitIndex) {
        return (inst >> bitIndex) & 1;
    }

    /**
     * 设置整数中的某一段的值
     *
     * @param inst  输入原始整数
     * @param value 要设置的值
     * @param bits  要设置的位的位置列表，value的每一位于bits中的位置一一对应
     * @return int 拼接后输出的整数
     */
    protected int setBits(int inst, int value, byte[] bits) {
        int ret = inst;
        for (int i = 0; i < bits.length; i++) {
            int valueBit = (value >> i) & 1;
            ret = setBit(ret, valueBit, bits[i]);
        }
        return ret;
    }

    /**
     * 设置整数中某一位的值
     *
     * @param inst     输入整数
     * @param value    要设置的值
     * @param bitIndex 要设置的位的位置
     * @return int 输出设置后的整数
     */
    private int setBit(int inst, int value, byte bitIndex) {
        int ret = inst & (~(1 << bitIndex));// 清除要设置的位
        ret |= (value << bitIndex); // 设置目标位为要设置的值
        return ret;
    }

    @Override
    public String toString() {
        String ret = super.toString();
        return ret.substring(0, ret.length() - 1) +
                ", \"fmt length\":\"" + fmtLength + "\"}";
    }

    protected String transToBinaryString(int value, int length) {
        StringBuilder stringBuilder = new StringBuilder(Integer.toBinaryString(value));
        int len = stringBuilder.length();
        // 将二进制字符串补足长度
        for (int i = 0; i < length - len; i++) {
            stringBuilder.insert(0, "0");
        }
        // 插入分割符
        for (int i = length - DIVIDE_LENGTH; i > 0; i -= DIVIDE_LENGTH) {
            stringBuilder.insert(i, "'");
        }
        return stringBuilder.toString();
    }
}
